from app.config.settings import settings
from app.utils.file_tools import clear_logs
from app.utils.logger import get_logger, setup_logging

import threading
from contextlib import asynccontextmanager

import time
from fastapi import FastAPI, Request
import uvicorn
from fastapi.middleware.cors import CORSMiddleware
from fastapi.openapi.utils import get_openapi
from starlette.staticfiles import StaticFiles

_logger_lock = threading.Lock()
_logger_initialized = False


def initialize_logger_once():
    """确保日志系统只初始化一次"""
    global _logger_initialized
    with _logger_lock:
        if not _logger_initialized:
            setup_logging()
            _logger_initialized = True


# 初始化日志配置
initialize_logger_once()

# 获取日志记录器
system_logger = get_logger('system')
app_logger = get_logger('app')
# 检查是否为调试模式
is_debug = settings.get('app.dev', False)

# 定义API示例数据
API_EXAMPLES = {
    "/ocr/text/file": {
        "post": {
            "requestBody": {
                "content": {
                    "multipart/form-data": {
                        "schema": {
                            "type": "object",
                            "properties": {
                                "images": {
                                    "type": "array",
                                    "items": {"type": "string", "format": "binary"},
                                    "description": "要识别的图像文件列表"
                                },
                                "language": {
                                    "type": "string",
                                    "enum": ["ch", "en", "fr", "german", "korean", "japan"],
                                    "default": "ch",
                                    "description": "识别语言，支持: ch(简体中文)、en(英文)、fr(法文)、german(德文)、korean(韩文)、japan(日文)"
                                },
                                "detail": {
                                    "type": "boolean",
                                    "default": False,
                                    "description": "是否返回详细信息，包括边界框和置信度"
                                }
                            }
                        },
                        "examples": {
                            "single_image": {
                                "summary": "单张图片示例",
                                "description": "上传单张图片进行OCR识别的示例",
                                "value": {}
                            },
                            "multiple_images": {
                                "summary": "多张图片示例",
                                "description": "上传多张图片进行OCR识别的示例",
                                "value": {}
                            }
                        }
                    }
                }
            }
        },
        "responses": {
            "200": {
                "description": "成功识别文本",
                "content": {
                    "application/json": {
                        "examples": {
                            "single_image": {
                                "summary": "单张图片识别结果",
                                "description": "当上传一张图片时的返回结果示例",
                                "value": {
                                    "msg": "ok",
                                    "data": [
                                        {
                                            "text": "你好世界",
                                            "bbox": [[10, 10], [100, 10], [100, 50], [10, 50]],
                                            "score": 0.98
                                        },
                                        {
                                            "text": "OCR识别",
                                            "bbox": [[10, 60], [120, 60], [120, 100], [10, 100]],
                                            "score": 0.95
                                        }
                                    ]
                                }
                            },
                            "multiple_images": {
                                "summary": "多张图片识别结果",
                                "description": "当上传多张图片时的返回结果示例",
                                "value": {
                                    "msg": "ok",
                                    "data": [
                                        [
                                            {
                                                "text": "第一张图片的文字",
                                                "bbox": [[10, 10], [100, 10], [100, 50], [10, 50]],
                                                "score": 0.98
                                            }
                                        ],
                                        [
                                            {
                                                "text": "第二张图片的文字",
                                                "bbox": [[15, 15], [120, 15], [120, 60], [15, 60]],
                                                "score": 0.96
                                            }
                                        ]
                                    ]
                                }
                            }
                        }
                    }
                }
            },
            "400": {
                "description": "请求参数错误",
                "content": {
                    "application/json": {
                        "example": {
                            "detail": "无效的语言参数或服务未正确配置"
                        }
                    }
                }
            },
            "500": {
                "description": "服务器内部错误",
                "content": {
                    "application/json": {
                        "example": {
                            "detail": "文本OCR文件上传处理失败: 错误信息"
                        }
                    }
                }
            }
        }
    }
}


# 自定义OpenAPI schema，实现描述内容的动态加载
def custom_openapi():
    # 总是重新生成schema以支持实时更新
    openapi_schema = get_openapi(
        title=app.title,
        version=app.version,
        description=app.description,
        routes=app.routes,
    )

    # 动态处理所有带有_description_file属性的路由
    if "paths" in openapi_schema:
        for route in app.routes:
            # 检查路由是否有endpoint属性（排除Mount等对象）
            if hasattr(route, 'endpoint'):
                # 检查路由是否有我们自定义的_description_file属性
                if hasattr(route.endpoint, '_description_file'):
                    # 获取路径和方法
                    path = route.path
                    method = route.methods.intersection({"GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"})
                    if method:
                        method = list(method)[0].lower()

                        # 检查该路径和方法在openapi_schema中是否存在
                        if path in openapi_schema["paths"] and method in openapi_schema["paths"][path]:
                            # 动态加载描述文件
                            try:
                                with open(route.endpoint._description_file, 'r', encoding='utf-8') as f:
                                    description = f.read()
                                    openapi_schema["paths"][path][method]["description"] = description
                            except FileNotFoundError:
                                openapi_schema["paths"][path][method]["description"] = "描述文件未找到"

                # 添加API示例数据
                path = route.path
                if path in API_EXAMPLES:
                    method = route.methods.intersection({"GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"})
                    if method:
                        method = list(method)[0].lower()
                        if method in API_EXAMPLES[path]:
                            # 合并示例数据到openapi_schema中
                            if path in openapi_schema["paths"] and method in openapi_schema["paths"][path]:
                                for key, value in API_EXAMPLES[path][method].items():
                                    if key == "responses":
                                        # 合并响应示例
                                        openapi_schema["paths"][path][method].setdefault("responses", {}).update(value)
                                    else:
                                        # 合并其他示例数据
                                        openapi_schema["paths"][path][method][key] = value

    app.openapi_schema = openapi_schema
    return app.openapi_schema


@asynccontextmanager
async def lifespan(app: FastAPI):
    # 开发模式下启动前清空日志文件内容
    is_clear_logs_on_start = settings.get('app.clear_logs_on_start', False)
    if is_debug and is_clear_logs_on_start:
        clear_logs()
    # 启动事件 - 使用系统日志记录器
    if system_logger:
        system_logger.info(f"{settings.get('app.name')} 启动中...")
        system_logger.info(f"监听地址: {settings.get('server.host')}:{settings.get('server.port')}")
        system_logger.info(f"应用: {app.title}, 版本: {app.version}, 调试模式: {is_debug}")
    else:
        print(f"{settings.get('app.name')} 启动中...")
        print(f"监听地址: {settings.get('server.host')}:{settings.get('server.port')}")
        print(f"应用: {app.title}, 版本: {app.version}, 调试模式: {is_debug}")

    # if system_logger:
    #     system_logger.info(f"FastAPI配置:\n{pformat(app.__dict__)}")
    # else:
    #     print(f"FastAPI配置:")
    #     print(pformat(app.__dict__))

    yield

    # 关闭事件 - 使用系统日志记录器
    if system_logger:
        system_logger.info(f"{settings.get('app.name')} 正在关闭...")
    else:
        print(f"{settings.get('app.name')} 正在关闭...")

    # 在调试模式下清理日志目录
    if is_debug:
        clear_logs()
        # # 删除logs目录
        # import shutil
        # shutil.rmtree('../logs')


# 创建FastAPI应用，使用 lifespan 参数
app = FastAPI(
    title=settings.get('app.name'),
    description="OCR service based on PaddleOCR",
    version=settings.get('app.version'),
    debug=is_debug,
    lifespan=lifespan,
    redoc_url="/redoc",
    docs_url="/docs",
)
# from app.api.routes import router
# # 包含路由
# app.include_router(router)

# 导入并包含主路由
from app.api.main_router import main_router

app.include_router(main_router)

# 设置自定义OpenAPI函数
app.openapi = custom_openapi

# 添加CORS中间件
app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"],
                   allow_headers=["*"], )

# 配置静态文件目录
app.mount("/static", StaticFiles(directory="static"), name="static")


@app.get("/")
async def root():
    # 业务请求使用普通日志记录器
    return {
        "message": f"欢迎使用 {settings.get('app.name')}",
        "version": settings.get('app.version'),
        "docs": "/docs",
        "redoc": "/redoc"
    }


@app.get("/health")
async def health_check():
    return {"status": "healthy"}


# --- 添加中间件 ---
@app.middleware("http")
async def log_requests_and_time(request: Request, call_next):
    """
    中间件：记录每个请求的基本信息和处理耗时。
    """
    if request.url.path.startswith("/api") or request.url.path.startswith("/ocr"):
        start_time = time.time()
        # 记录请求开始
        app_logger.info(f"Received request: {request.client.host} {request.method} {request.url.path}")

        # if request.url.path != "/" or request.url.path != "/docs" or request.url.path != "/redoc" or request.url.path != "/openapi.json" or request.url.path != "/openapi.json":

        try:
            # 处理请求
            response = await call_next(request)
        except Exception as e:
            # 如果在处理请求时发生异常，也记录下来
            process_time = time.time() - start_time
            app_logger.error(
                f"Request failed: {request.method} {request.url.path} - Error: {e} - Time: {process_time:.2f}s")
            raise  # 重新抛出异常，让 FastAPI 的默认异常处理器处理

        # 计算耗时
        process_time = time.time() - start_time
        # response.headers["X-Process-Time"] = f"{process_time:.4f}"  # 可选：添加到响应头

        # 记录请求结束和耗时
        app_logger.info(
            f"Completed request: {request.method} {request.url.path} - Status: {response.status_code} - Time: {process_time:.2f}s\n")
    else:
        # 如果不是 API 请求，则不记录
        response = await call_next(request)
    return response


# --- 中间件结束 ---

if __name__ == "__main__":
    main_logger = get_logger(__name__)
    try:
        uvicorn.run(
            "app.main:app",
            host=settings.get('server.host'),
            port=settings.get('server.port'),
            log_level=settings.get('server.log_level'),
            access_log=settings.get('server.access_log'),
            loop="asyncio",
            http="h11",
            workers=settings.get('server.workers'),
            reload=settings.get('server.reload'),
            reload_dirs=settings.get('server.reload_dirs'),
            limit_concurrency=settings.get('server.limit_concurrency'),
            timeout_keep_alive=settings.get('server.timeout_keep_alive'),
            log_config={
                "version": 1,
                "disable_existing_loggers": False,
                "formatters": {
                    "default": {
                        "()": "uvicorn.logging.DefaultFormatter",
                        # "fmt": "%(asctime)s - %(levelprefix)s %(message)s",
                        "fmt": "%(asctime)s - %(levelname)s - [%(name)s] - %(filename)s:%(lineno)d - %(message)s",
                        "datefmt": "%Y-%m-%d %H:%M:%S",
                    },
                    "access": {
                        "()": "uvicorn.logging.AccessFormatter",
                        "fmt": '%(asctime)s - %(levelname)s - %(client_addr)s - "%(request_line)s" %(status_code)s',
                    }
                },
                "handlers": {
                    "default": {
                        "formatter": "default",
                        "class": "logging.FileHandler",
                        "filename": "../logs/uvicorn.log",
                        "mode": "a",
                        "encoding": "utf-8",
                    },
                    "console": {
                        "formatter": "default",
                        "class": "logging.StreamHandler",  # 输出到控制台
                        "stream": "ext://sys.stderr"
                    },
                    "access": {
                        "formatter": "default",
                        "class": "logging.FileHandler",
                        "filename": "../logs/access.log",
                        "mode": "a",
                        "encoding": "utf-8",
                    },
                    "rotating_file": {
                        "formatter": "default",
                        "class": "logging.handlers.RotatingFileHandler",
                        "filename": "../logs/uvicorn.log",
                        "maxBytes": 10485760,  # 10MB
                        "backupCount": 5,
                        "encoding": "utf-8",
                    },
                    "timed_rotating_file": {
                        "formatter": "default",
                        "class": "logging.handlers.TimedRotatingFileHandler",
                        "filename": "../logs/uvicorn.log",
                        "when": "midnight",
                        "interval": 1,
                        "backupCount": 30,
                        "encoding": "utf-8",
                    }
                },
                "loggers": {
                    "uvicorn": {"handlers": ["default", "console"], "level": "INFO", "propagate": False},
                    "uvicorn.error": {"level": "INFO"},
                    "uvicorn.access": {"handlers": ["access"], "level": "INFO", "propagate": False},
                },
            }
        )
    except Exception as e:
        main_logger.error(f"Uvicorn server failed to start: {str(e)}", exc_info=True)
        import sys

        sys.exit(1)
        # raise
